jQuery.fn.serializeObject = function()
{
    var o = {};
    var a = this.serializeArray();
    jQuery.each(a, function() {
        if (o[this.name] !== undefined) {
            if (!o[this.name].push) {
                o[this.name] = [o[this.name]];
            }
            o[this.name].push(this.value || '');
        } else {
            o[this.name] = this.value || '';
        }
    });
    return o;
}; 


/**
 * Fix change event with keyboard in radiobuttons
 * @see http://stackoverflow.com/questions/4028936/change-event-not-firing-when-radio-button-is-selected-with-keyboard
 */
jQuery.fn.fix_radios = function() {
	  function focus() {
	    if ( !this.checked ) return;
	    if ( !this.was_checked ) {
	      $( this ).change();
	    }
	  }

	  function change( e ) {
	    if ( this.was_checked ) {
	      e.stopImmediatePropagation();
	      return;
	    }
	    $( "input[name=" + this.name + "]" ).each( function() {
	      this.was_checked = this.checked;
	    } );
	  }
	  return this.focus( focus ).change( change );
	};
	
	
	
	
	
	
	/* Title: Observer
	 * Description: is a publish/subscribe pattern which allows a number of observer objects to see an event
	 * Tutorial: https://github.com/shichuan/javascript-patterns/blob/master/design-patterns/observer.html
	 */
	var observer = {
			addSubscriber:function (callback) {
				this.subscribers[this.subscribers.length] = callback;
			},
			removeSubscriber:function (callback) {
				for (var i = 0; i < this.subscribers.length; i++) {
					if (this.subscribers[i] === callback) {
						delete(this.subscribers[i]);
					}
				}
			},
			publish:function (what) {
				for (var i = 0; i < this.subscribers.length; i++) {
					if (typeof this.subscribers[i] === 'function') {
						this.subscribers[i](what);
					}
				}
			},
			make:function (o) { // turns an object into a publisher
				for (var i in this) {
					o[i] = this[i];
					o.subscribers = [];
				}
			}
		};	
	
	
	
	
	/**
	 * Clear form data with jQuery
	 * @see http://www.jquery4u.com/forms/jquery-function-clear-form-data/
	 */
	jQuery.fn.clearForm = function() {
		return this.each(function() {
			var type = this.type, tag = this.tagName.toLowerCase();
			if (tag == 'form')
				return jQuery(':input',this).clearForm();
			if (type == 'text' || type == 'password' || tag == 'textarea')
				this.value = '';
			else if (type == 'checkbox' || type == 'radio')
				this.checked = false;
			else if (tag == 'select')
				this.selectedIndex = -1;
			});
		};

		
		
		
	

	/**
	 * Check if object passed as parameter is an array object
	 * @param a
	 * @returns {Boolean}
	 * {@link http://studiokoi.com/blog/article/typechecking_arrays_in_javascript}
	 */
	function isArray(a)
	{
		return Object.prototype.toString.apply(a) === '[object Array]';
	}

	



Event_Driver.prototype.events_Stack = [];
Event_Driver.prototype.delta_Trigger = 1200;
Event_Driver.prototype.last_TriggerTime = 0;
Event_Driver.prototype.last_EventTime = 0;


Event_Driver.prototype.add_Event = function (time, event_Object) {
	
	
	if (time <= this.last_EventTime || time <= this.last_TriggerTime) {
		return;
	}
	
	
	var new_Event = {"time" : time,
	                 "object": event_Object};
	
	this.events_Stack.unshift(new_Event);
	
	this.last_EventTime = time;
	
};



Event_Driver.prototype.check_Events = function () {
	
	var result = false;
	
	
	var date = new Date();
	var time = date.getTime();
	var stack_ID_old = -1;
	
	
	if (time - this.last_TriggerTime > this.delta_Trigger) {

		for ( var int = 0; int < this.events_Stack.length; int++) {

			var event_Object = this.events_Stack[int];
			
			if (event_Object['time'] > this.last_TriggerTime) {
				stack_ID_old = int;
			}
		}
	} 

	
	if (stack_ID_old >= 0) {
		this.events_Stack = this.events_Stack.slice(stack_ID_old);
		
		result = true;
		
		this.last_TriggerTime = time;
	}
	

	return result;
};




/**
 * Notity event method
 * @param {MBE_ECOM_Step_Price_Item_Event} event
 * @param time
 * @param {Object} item
 */
Event_Driver.prototype.notifyEvent = function(event, time, item) {
	
	if (item == null) {
		item = this;
	}
	
	var event_Driver = this;
	
	if (time == null) {
		var date = new Date();
		time = date.getTime();
	}
	

	if (time < this.last_TriggerTime) { // Check las event trigger
		return;
	}
	
	this.add_Event(time, event); // Add event to Event driver
	
	
	if (this.check_Events()) {  // Check events
		
		jQuery(item).trigger(event.eventType, event);
		
	} else {
		
		setTimeout(function() {  // Notify item next (event delay)
			event_Driver.notifyEvent(event, time, item);
		},this.delta_Trigger + 10);
		
	}
	
};





/**
 * Basic event driver
 * @returns {Event_Driver}
 */
function Event_Driver() {
	
	
	var date = new Date();
	this.last_TriggerTime = date.getTime();
	

};





/**
 * Console log trick (Not for IE)
 * @param param
 */
function console_Log(param) {
	if (!jQuery.browser.msie) {
		console.log(param);
	}
}


/**
 * Clobe objects support
 */
//Object.prototype.clone = function() {
//	  var newObj = (this instanceof Array) ? [] : {};
//	  for (i in this) {
//	    if (i == 'clone') continue;
//	    if (this[i] && typeof this[i] == "object") {
//	      newObj[i] = this[i].clone();
//	    } else newObj[i] = this[i]
//	  } return newObj;
//	};
	

/**
 * JavaScript object copy facility
 * @see http://james.padolsey.com/javascript/deep-copying-of-objects-and-arrays/
 * @since 05-11-2012
 */
function deepCopy(o) {
    var copy = o,k;
 
    if (o && typeof o === 'object') {
        copy = Object.prototype.toString.call(o) === '[object Array]' ? [] : {};
        for (k in o) {
            copy[k] = deepCopy(o[k]);
        }
    }
 
    return copy;
}



/**
 * This function check if a NIF is valid
 * 
 * @see http://www.diegodicamillo.com.ar/blog/2010/08/03/conjunto-de-funciones-javascript-para-validar-email-nif-cif-telefono-fijo-y-telefono-movil/
 * 
 * @param abc
 * @returns {Boolean}
 */
function isValidNif(abc){
	dni=abc.substring(0,abc.length-1);
	let=abc.charAt(abc.length-1);
	if (!isNaN(let)) {
		//alert('Falta la letra');
		return false;
	}else{
		cadena = "TRWAGMYFPDXBNJZSQVHLCKET";
		posicion = dni % 23;
		letra = cadena.substring(posicion,posicion+1);
		if (letra!=let.toUpperCase()){
			//alert("Nif no válido");
			return false;
		}
	}
	//alert("Nif válido")
	return true;
}



//Retorna: 1 = NIF ok, 2 = CIF ok, 3 = NIE ok, -1 = NIF error, -2 = CIF error, -3 = NIE error, 0 = ??? error
/**
 * Retorna: 1 = NIF ok, 2 = CIF ok, 3 = NIE ok, -1 = NIF error, -2 = CIF error, -3 = NIE error, 0 = ??? error
 * @tutorial http://www.compartecodigo.com/javascript/validar-nif-cif-nie-segun-ley-vigente-31.html
 */
function valida_nif_cif_nie( a )
{
	var temp = a.toUpperCase();
	var cadenadni = "TRWAGMYFPDXBNJZSQVHLCKE";
 
	if( temp!= '' )
	{
		//si no tiene un formato valido devuelve error
		if( ( !/^[A-Z]{1}[0-9]{7}[A-Z0-9]{1}$/.test( temp ) && !/^[T]{1}[A-Z0-9]{8}$/.test( temp ) ) && !/^[0-9]{8}[A-Z]{1}$/.test( temp ) )
		{
			return 0;
		}
 
		//comprobacion de NIFs estandar
		if( /^[0-9]{8}[A-Z]{1}$/.test( temp ) )
		{
			posicion = a.substring( 8,0 ) % 23;
			letra = cadenadni.charAt( posicion );
			var letradni = temp.charAt( 8 );
			if( letra == letradni )
			{
				return 1;
			}
			else
			{
				return -1;
			}
		}
 
 
		//algoritmo para comprobacion de codigos tipo CIF
		suma = parseInt(a.charAt(2))+parseInt(a.charAt(4))+parseInt(a.charAt(6));
 
		for( var i = 1; i < 8; i += 2 )
		{
			temp1 = 2 * parseInt( a.charAt( i ) );
			temp1 += '';
			temp1 = temp1.substring(0,1);
			temp2 = 2 * parseInt( a.charAt( i ) );
			temp2 += '';
			temp2 = temp2.substring( 1,2 );
			if( temp2 == '' )
			{
				temp2 = '0';
			}
 
			suma += ( parseInt( temp1 ) + parseInt( temp2 ) );
		}
		suma += '';
		n = 10 - parseInt( suma.substring( suma.length-1, suma.length ) );
 
		//comprobacion de NIFs especiales (se calculan como CIFs)
		if( /^[KLM]{1}/.test( temp ) )
		{
			if( a.charAt( 8 ) == String.fromCharCode( 64 + n ) )
			{
				return 1;
			}
			else
			{
				return -1;
			}
		}
 
		//comprobacion de CIFs
		if( /^[ABCDEFGHJNPQRSUVW]{1}/.test( temp ) )
		{
			temp = n + '';
			if( a.charAt( 8 ) == String.fromCharCode( 64 + n ) || a.charAt( 8 ) == parseInt( temp.substring( temp.length-1, temp.length ) ) )
			{
				return 2;
			}
			else
			{
				return -2;
			}
		}
 
		//comprobacion de NIEs
		//T
		if( /^[T]{1}[A-Z0-9]{8}$/.test( temp ) )
		{
			if( a.charAt( 8 ) == /^[T]{1}[A-Z0-9]{8}$/.test( temp ) )
			{
				return 3;
			}
			else
			{
				return -3;
			}
		}
		//XYZ
		if( /^[XYZ]{1}/.test( temp ) )
		{
			temp = temp.replace( 'X','0' );
			temp = temp.replace( 'Y','1' );
			temp = temp.replace( 'Z','2' );
			pos = temp.substring(0, 8) % 23;
 
			if( a.toUpperCase().charAt( 8 ) == cadenadni.substring( pos, pos + 1 ) )
			{
				return 3;
			}
			else
			{
				return -3;
			}
		}
	}
 
	return 0;
}

